﻿using System;
using System.Collections.Generic;
using System.Net.Sockets;
using UnityEngine;
using LitJson;
using System.Text;
using System.Net;

public class NetManager : MonoBehaviour
{
    private const bool Log_Enable = false;

    private static NetManager m_Inst;
    public static NetManager Instance
    {
        get { return m_Inst; }
    }

    private MyTcpAcceptConn m_AcceptConn;
    private string m_Status = ""; //只在渲染线程上操作
    private Queue<SocketHelper.ThreadMessage> m_ThreadMessageQueue = new Queue<SocketHelper.ThreadMessage>();

    public MyTcpServerConn m_ServerConn;
    public MyTcpClientConn m_ClientConn;

    public NetManager()
    {
        if (null == m_Inst)
            m_Inst = this;
        else
            Debug.LogError($"multi Instance");
    }

    void OnDestroy()
    {
        if (this == m_Inst) m_Inst = null;

        if (null != m_ServerConn)
        {
            m_ServerConn.Close();
            m_ServerConn = null;
        }

        if (null != m_ClientConn)
        {
            m_ClientConn.Stop();
            m_ClientConn = null;
        }
    }

    //******************** server

    public MyTcpAcceptConn AcceptConn
    {
        get { return m_AcceptConn; }
    }

    public MyTcpServerConn ServerConn
    {
        get { return m_ServerConn; }
    }

    public MyTcpServerConn CreateServerConn()
    {
        m_ServerConn = new MyTcpServerConn(m_ThreadMessageQueue);
        return m_ServerConn;
    }

    public void CloseServer()
    {
        //if (null != m_ServerConn)
        {
            m_ServerConn.Close();
            m_ServerConn = null;
        }
    }

    public void SendToClient(string str)
    {
        if (null != m_AcceptConn)
        {
            m_AcceptConn.Send(str);
        }
    }

    //********************

    //******************** client

    public MyTcpClientConn ClientConn
    {
        get { return m_ClientConn; }
    }

    public MyTcpClientConn CreateClientConn()
    {
        m_ClientConn = new MyTcpClientConn(m_ThreadMessageQueue);
        return m_ClientConn;
    }

    public void ClientConnect(IPEndPoint serverAddress)
    {
        if (null == m_ClientConn)
            m_ClientConn = new MyTcpClientConn(m_ThreadMessageQueue);

        m_ClientConn.SetServerAddress(serverAddress);
        m_ClientConn.ConnectServer();
    }

    public void CloseClient()
    {
        //if (null != m_ClientConn)
        {
            m_ClientConn.Stop();
            m_ClientConn = null;
        }
    }

    public void SendToServer(string str)
    {
        m_ClientConn.Send(str);
    }

    //********************

    //******************** 消息队列(渲染线程转发)

    void Update()
    {
        CheckThreadMessageQueue();
    }

    private void CheckThreadMessageQueue()
    {
        if (m_ThreadMessageQueue.Count > 0)
        {
            lock (m_ThreadMessageQueue)
            {
                while (m_ThreadMessageQueue.Count > 0)
                {
                    var cmd = m_ThreadMessageQueue.Dequeue();
                    OnThreadMessage(cmd);
                }
            }
        }
    }

    //********************

    //渲染线程上执行
    private void OnThreadMessage(SocketHelper.ThreadMessage msg)
    {
        if (Log_Enable) Debug.Log($"server: OnThreadMessage: {msg.m_Cmd}");

        switch (msg.m_Cmd)
        {
        case "Server.Accept":
            m_Status = msg.m_Cmd;
            m_AcceptConn = (MyTcpAcceptConn) msg.m_Obj;
            MsgDispatch.Instance.Dispatch(msg.m_Cmd, null);
            break;

        case "Server.ClientDisconnect":
            MsgDispatch.Instance.Dispatch(msg.m_Cmd, null);
            if (m_AcceptConn == msg.m_Obj)
            {
                m_AcceptConn = null;
                m_ServerConn.BeginAccepting();
            }
            break;

        case "Server.ClientPacket":
            OnServerRecvPacket((MyTcpAcceptConn)msg.m_Obj, msg.m_Content);
            break;

        case "Client.Connected":
        case "Client.ConnectFail":
        case "Client.Disconnect": //与服务器断开
            m_Status = msg.m_Cmd;
            MsgDispatch.Instance.Dispatch(msg.m_Cmd, null);
            break;

        case "Client.ServerPacket":
            OnClientRecvPacket(msg.m_Content);
            break;

        }
    }

    //服务器收到客户端数据包
    private void OnServerRecvPacket(MyTcpAcceptConn conn, string jsonStr)
    {
        try
        {
            JsonData data = JsonMapper.ToObject(jsonStr);
            var msg = (string)data["msg"];
            bool haveReceiver = MsgDispatch.Instance.Dispatch($"{msg}.Server", data);
            switch (msg)
            {
            case "Join":
                if (!haveReceiver && null != m_AcceptConn && m_AcceptConn == conn)
                {
                    var respData = new JsonData();
                    respData["msg"] = "Join";
                    respData["code"] = 2;
                    conn.Send(respData.ToJson());
                }
                break;
            }
        }
        catch (Exception ex)
        {
            Debug.LogError($"{ex.Message}\n{ex.StackTrace}");
        }
    }

    //客户端收到服务器数据包
    private void OnClientRecvPacket(string jsonStr)
    {
        try
        {
            JsonData data = JsonMapper.ToObject(jsonStr);
            var msg = (string)data["msg"];
            MsgDispatch.Instance.Dispatch(msg, data);     
        }
        catch (Exception ex)
        {
            Debug.LogError($"{ex.GetType().Name}: {ex.Message}");
        }
    }

    public void ServerSendChessDownNoti(int turn, int row, int col)
    {
        if (null == m_AcceptConn) return;

        var socketData = new JsonData();
        socketData["msg"] = "ChessDownNoti";
        socketData["x"] = col;
        socketData["y"] = row;
        socketData["turn"] = turn;
        m_AcceptConn.Send(socketData.ToJson());
    }

    public void ClientSendReady(bool b)
    {
        if (null == m_ClientConn) return;

        var socketData = new JsonData();
        socketData["msg"] = "Ready";
        socketData["color"] = 2;
        socketData["b"] = b;
        m_ClientConn.Send(socketData.ToJson());
    }

    public void ClientSendChessDown(int turn, int row, int col)
    {
        if (null == m_ClientConn) return;

        var socketData = new JsonData();
        socketData["msg"] = "ChessDown";
        socketData["x"] = col;
        socketData["y"] = row;
        socketData["turn"] = turn;
        m_ClientConn.Send(socketData.ToJson());
    }



}
